package tech.yixiyun.framework.kuafu.controller.request;

import com.fasterxml.jackson.databind.JsonNode;
import tech.yixiyun.framework.kuafu.controller.action.ActionContext;
import tech.yixiyun.framework.kuafu.controller.request.param.ParamUtil;
import tech.yixiyun.framework.kuafu.kits.HttpKit;
import tech.yixiyun.framework.kuafu.kits.JSONKit;
import tech.yixiyun.framework.kuafu.kits.StringKit;
import org.apache.commons.io.IOUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.*;

/**
 * 框架对httpservletrequest的又一层封装
 */
public class KuafuRequest extends HttpServletRequestWrapper {

    /**
     * 原请求
     */
    private HttpServletRequest originalRequest;

    public static final String CONTENTTYPE_JSON = "application/json";

    public static final String CONTENTTYPE_MULTIPART = "multipart/form-data";

    /**
     * 请求体
     */
    private byte[] body;

    public KuafuRequest(HttpServletRequest request) {
        super(request);
        this.originalRequest = request;

    }



    /**
     * 将请求参数根据参数名进行分组，每个组里是key对应的参数的所有数据
     */
    private Map<String, List<Map.Entry<String, String[]>>> commonParameterMap;
    /**
     * 针对普通请求,将请求参数转成map。
     * map的key 对应顶级参数名，value是这个顶级参数相关的所有参数列表。
     * @return
     */
    public Map<String, List<Map.Entry<String, String[]>>> getCommonParameterMap() {
        if (commonParameterMap == null) {
            commonParameterMap = new HashMap<>();
            Map<String, String[]> parameterMap =  resolveCommonRequestParameters();
            if (parameterMap != null && parameterMap.isEmpty() == false) {
                Iterator<Map.Entry<String, String[]>> iterator = parameterMap.entrySet().iterator();
                String key;
                while (iterator.hasNext()) {
                    Map.Entry<String, String[]> item = iterator.next();
                    key = ParamUtil.clean(item.getKey());
                    List<Map.Entry<String, String[]>> groupItems = commonParameterMap.get(key);
                    if (groupItems == null) {
                        groupItems = new ArrayList<Map.Entry<String, String[]>>();
                        commonParameterMap.put(key, groupItems);
                    }
                    groupItems.add(item);
                }
            }
        }
        return commonParameterMap;
    }

    /**
     * 解析普通请求的请求参数
     * @return
     */
    private Map<String, String[]> resolveCommonRequestParameters(){
        HashMap<String,String[]> requestParams= new HashMap<>(originalRequest.getParameterMap());
        if (isMultipartRequest()) {
            UploadHelper.resolveMultipartParameters(this.originalRequest, requestParams);
        }
        return requestParams;
    }





    /**
     * json请求拆解的参数，value的就是key对应的json对象字符串
     */
    private Map<String, JsonNode> jsonParameterMap;

    /**
     * 针对contentType是 application/json的请求，将请求参数转成map。
     * map中的key对应json数据的最顶层key，map中的value对应json数据中相应的value转换成的jsonnode对象。
     *
     * @return
     */
    public Map<String, JsonNode> getJSONParameterMap() {
        if (jsonParameterMap == null && isJSONRequest()) {
            String body = getRequestBodyAsString();
            if (StringKit.isBlank(body)) {
                jsonParameterMap = new HashMap<>();
            } else {
                jsonParameterMap = JSONKit.toObjectMap(body, String.class, JsonNode.class);
            }
        }

        return jsonParameterMap;
    }


    private Map<Integer, String> urlParameterMap;
    /**
     * 获取 urlParam的参数并转化成map，key是下标，value是字符串类型的值
     * @return
     */
    public Map<Integer, String> getUrlParameterMap() {
        if (urlParameterMap == null) {
            String uri = getRequestURI();
            if (uri.length() > 1 && uri.endsWith("/")) { //如果请求参数是 /a/1-1/ ，要把最后一个/去掉，变成 /a/1-1
                uri = uri.substring(0, uri.length() - 1);
            }
            String routeUri = ActionContext.getAction().getRoute().getPath();
            if (routeUri.endsWith("/") == false) { //路由路径是 /a，我们要在最后加个 /，变成 /a/
                routeUri += "/";
            }
            if (uri.length() > routeUri.length()) {
                String[] params = uri.substring(routeUri.length()).split("/"); //这样就能获取到 1-1了
                Map<Integer, String> map = new HashMap<>(8);
                for (int i = 0; i < params.length; i++) {
                    map.put(i, params[i]);
                }
                urlParameterMap =  map;
            } else {
                urlParameterMap = Collections.emptyMap();
            }
        }

        return urlParameterMap;

    }




    /**
     * 判断是否是ajax异步请求，判断依据是： <br/>
     * 1.如果contentType是application/json，就认为是ajax请求<br/>
     * 2.如果header中有x-requested-with=XMLHttpRequest 就认为是ajax请求
     * @return
     */
    public boolean isAjaxRequest() {
        boolean isAjax = getContentType() != null && getContentType().contains(CONTENTTYPE_JSON);

        if (isAjax) {
            return true;
        }

        String xrequestedwith = getHeader("x-requested-with");
        if (xrequestedwith == null) {
            isAjax = false;
        } else if (xrequestedwith.equalsIgnoreCase("XMLHttpRequest")) {
            isAjax = true;
        }
        return isAjax;
    }

    /**
     * 请求的contentType是否是 multipart/form-data
     * @return
     */
    public boolean isMultipartRequest() {
        String contentType = originalRequest.getContentType();
        return contentType != null && contentType.toLowerCase().contains(CONTENTTYPE_MULTIPART);
    }


    /**
     * 是否是json请求，依据是contentType 中包含 application/json
     * @return
     */
    public boolean isJSONRequest() {
        String contentType = originalRequest.getContentType();
        return contentType != null && contentType.toLowerCase().contains(CONTENTTYPE_JSON);
    }


    /**
     * 读取请求体，并转成byte数组
     * @return
     */
    public byte[] getRequestBody() {
        if (body == null) {
            try (InputStream is = originalRequest.getInputStream()){
                body = IOUtils.toByteArray(is);
            } catch (IOException e) {
                throw new RuntimeException("解析请求体时，发生异常", e);
            }
        }
        return body;
    }


    /**
     * 读取请求体，并转为string，使用默认字符集
     * @return
     */
    public String getRequestBodyAsString() {
        byte[] body = getRequestBody();
        if (body == null) {
            return null;
        }
        return new String(body);
    }
    /**
     * 读取请求体，并转为string，使用指定字符集
     * @return
     */
    public String getRequestBodyAsString(String encoding) {
        byte[] body = getRequestBody();
        if (body == null) {
            return null;
        }
        try {
            return new String(body, encoding);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return null;
        }
    }





    /**
     * 获取原始的HttpServletRequest请求对象
     * @return
     */
    public HttpServletRequest getOriginalRequest() {
        return this.originalRequest;
    }

    /**
     * 获取本次请求的ip地址
     * @return
     */
    public String getIpAddress() {
        return HttpKit.getIPAddress(originalRequest);
    }

}
